﻿/*
 * db_sqlite.cpp
 *
 *  Created on: 2017年3月11日
 *      Author: work
 */

#include <dm/export.hpp>

#define DM_API_OS_DB DM_API_EXPORT

#include <dm/os/db/db_sqlite.hpp>
#include <dm/env/env.hpp>
#include <string>
#include <dm/os/log/logger.hpp>

#ifdef WIN32
#include <windows.h>
static void usleep( unsigned long usec ){
	Sleep(usec/1000);
}

#endif

namespace dm{
namespace os{

static const char* logModule = "CDbSqlite.os.dm";

CDbSqlite::CDbSqlite(const char* dbName,const char* host,short port):CDb(dbName,host,port),
		m_db(0){
}

CDbSqlite::~CDbSqlite(){
	if( m_db!=0 ){
		if( SQLITE_OK!=sqlite3_close(m_db) ){
			log().warnning( THISMODULE "关闭数据%s失败：%s",m_dbName.c_str(),sqlite3_errmsg(m_db));
			sqlite3_close_v2(m_db);
		}
	}
}

CDb::EDbType CDbSqlite::dbType(){
	return DtSqlite;
}

bool CDbSqlite::isConnected(){
	return m_db!=0;
}

bool CDbSqlite::connect( const char*,const char* ){
	if( m_db ){
		log().info(THISMODULE "数据库已经打开");
		return true;
	}

	std::string dbFile = dm::env::getCfgDir()+'/'+m_dbName+".db3";
	int rc = sqlite3_open(dbFile.c_str(),&m_db);
	if( rc==SQLITE_OK ){
		log().debug(THISMODULE "打开数据库%s",dbFile.c_str());
		//sqlite3_busy_timeout(m_db,1000);
		return true;
	}else{
		log().warnning( THISMODULE "打开数据%s失败：%s",dbFile.c_str(),sqlite3_errmsg(m_db));
		return false;
	}
}

void CDbSqlite::disconnect(){
	if( m_db!=0 ){
		if( SQLITE_OK!=sqlite3_close(m_db) ){
			log().warnning( THISMODULE "关闭数据%s失败：%s",m_dbName.c_str(),sqlite3_errmsg(m_db));
			sqlite3_close_v2(m_db);
		}
		m_db = 0;
	}
}

bool CDbSqlite::exec( const char* sql ){
	if( m_db!=0 ){
		int rt;
		int cnt = 0;
		while( true ){
			rt = sqlite3_exec(m_db,sql,0,0,0);
			if( rt==SQLITE_LOCKED || rt==SQLITE_BUSY ){
				if( cnt>100 )
					break;
				++cnt;
				usleep(100000);
			}else
				break;
		}

		if( rt==SQLITE_OK )
			return true;
		else{
			log().warnning(THISMODULE "执行失败：'%s' : %s",sql,sqlite3_errmsg(m_db));
			return false;
		}
	}

	return false;
}

dm::int64 CDbSqlite::execWithLastId( const char* sql ){
	if( !exec(sql) )
		return -1;

	return sqlite3_last_insert_rowid(m_db);
}

CResultSet* CDbSqlite::query( const char* sql ){
	if( m_db!=0 ){
		int rt;
		int cnt = 0;

		CResultSetSqlite* rs = new CResultSetSqlite();

		while( true ){
			rt = sqlite3_prepare(m_db,sql,-1,&rs->m_stmt,0);
			if( rt==SQLITE_LOCKED || rt==SQLITE_BUSY ){
				if( cnt>100 )
					break;
				++cnt;
				usleep(100000);
			}else
				break;
		}

		if( SQLITE_OK!=rt ){
			log().warnning(THISMODULE "执行语句失败 '%s' :%s",sql,sqlite3_errmsg(m_db));
			delete rs;
			return NULL;
		}else{
			rs->m_size = 0;
			while( sqlite3_step(rs->m_stmt)==SQLITE_ROW ){
				++rs->m_size;
			}

			sqlite3_reset(rs->m_stmt);
			return rs;
		}
	}

	log().debug(THISMODULE "sqlite库未打开");
	return NULL;
}

/**
 * 获取匹配字符串表名
 * @param pattern
 * @param rs
 * @return
 */
CResultSet* CDbSqlite::getTables( const char* pattern ){
	std::string sql = "select tbl_name from sqlite_master where type='table' and tbl_name like '";
	sql += pattern;
	sql += "'";

	return query(sql.c_str());
}

}
}
